<script lang="ts" setup>
import VFormItem from './form-item.vue'
import {DataFormProps, DataFormConfig} from "./interface";
import {FormInstance} from "element-plus";
import SvgIcon from "@/components/svg-icon/index.vue";
import {nextTick, onBeforeMount, onMounted, reactive, ref, useSlots} from "vue";
import {validator} from "@/utils";

const props = withDefaults(defineProps<DataFormProps>(), {
    disabled: false,
    width: '30%',
    labelWidth: 'auto',
    footer: true,
    ruleField: undefined,
    beforeSubmit: (done: any) => done(),
});

const formRef = ref<FormInstance>();
const config = reactive<DataFormConfig>({
    mode: 'get',
    title: '查看',
    icon: 'search',
    visible: false,
    loading: false,
})
const modelData = ref<Record<string, any>>(props.model || {});
const attrs = ref<any>({}); // 自定义属性

onBeforeMount(() => {
    // 表单对象为空时则根据组件配置动态生成
    if (!props.model && props.forms) {
        for (let form of props.forms) {
            if (form.prop) {
                modelData.value[form.prop] = typeof form.value !== 'undefined'? form.value : null;
            }
        }
    }
    if (props.ruleProp) {
        attrs.value['rule'] = props.ruleProp; // 用于动态适配i18n语言
    }
})

// 打开弹窗
let submit: ((resolve: (value: any) => void, form: Record<string, any>, type: AxiosMethod) => void) | undefined;
const open = (options: OpenFormConfig): void => {
    // 标记本次动作类型
    submit = options.confirm;
    config.mode = options.type || (options.data? 'put':'post');
    config.title = props.title || ((config.mode === 'put'? '编辑':'创建') + props.description);
    config.icon = config.mode === 'put'? 'edit-pen':'edit';
    // 显示弹窗并加载数据
    config.visible = true;
    // if (!props.model && props.forms && options.data) {
    if (options.data) {
        nextTick(() => {
            Object.keys(modelData.value).forEach(item => modelData.value[item] = options.data[item]);
        })
    }
}

//提交表单
const confirm = () => {
    new Promise((resolve) => {
        props.beforeSubmit(resolve);
    }).then(status => {
        if (status !== false) {
            formRef.value?.validate((valid: boolean): void => {
                if (valid) {
                    config.loading = true;
                    const func = new Promise(resolve => submit?.(resolve, modelData.value, config.mode))
                    func.then((result?: any) => {
                        if ((typeof result === 'undefined') || (typeof result === 'number' && result === 200) || (typeof result === 'boolean' && result)) close();
                    }).finally(() => {
                        config.loading = false
                    })
                }
            })
        }
    })
}

// 关闭弹窗
const close = () => {
    formRef.value?.resetFields();
    config.visible = false;
}

const slots = useSlots();
onMounted(() => {
    nextTick(() => {
        if (slots.default && props.ruleField) {
            const tempRules: {[key:string]:any} = {};
            slots.default?.()?.filter((item: any) => item.type.name === "ElFormItem" && props.ruleField?.includes(item.props.prop))
                    ?.forEach((item: any) => {
                        tempRules[item.props.prop] = [{required: item.props.required??true, trigger: 'blur', group: props.ruleProp, validator: validator}];
                    });
            attrs.value['rules'] = tempRules;
        }
    })
})

// 暴露接口
defineExpose({open})
</script>

<template>
    <el-dialog v-model="config.visible" :close-on-click-modal="false" :show-close="false" :width="width" align-center destroy-on-close draggable overflow>
        <template #header="{ titleId, titleClass }">
            <div class="dialog-header">
                <div class="dialog-header--title">
                    <el-icon :size="18" style="margin-right: 5px">
                        <svg-icon :icon="config.icon"/>
                    </el-icon>
                    <span :id="titleId" :class="titleClass">{{ config.title }}</span>
                </div>
                <el-button class="dialog-header--close" @click="close()" link>
                    <template #icon>
                        <svg-icon icon="close"/>
                    </template>
                </el-button>
            </div>
        </template>
        <el-form ref="formRef" :label-width="labelWidth" :model="modelData" label-position="right" :disabled="disabled" v-bind="attrs">
            <template v-for="(item, index) in forms" v-if="forms && forms.length > 0" :key="index">
                <slot v-if="item.slot"
                      :form="item"
                      :model="modelData"
                      :name="typeof item.slot === 'boolean'? item.prop:item.slot">
                    <!--自定义单个表单项-->
                </slot>
                <v-form-item v-else-if="!!item.prop"
                             v-model="modelData[item.prop]"
                             :attrs="item.attrs"
                             :data="item.data"
                             :disabled="item.disabled"
                             :el="item.el"
                             :label="item.label"
                             :prop="item.prop"
                             :option="enums?.[item.prop]"
                             :required="item.required"/>
            </template>
            <slot v-else>
                <!--自定义所有表单项-->
            </slot>
        </el-form>
        <template v-if="footer" #footer>
            <el-button type="danger" @click="close()">取消</el-button>
            <el-button v-if="config.mode !== 'get'" :loading="config.loading" type="primary" @click="confirm()">确定</el-button>
        </template>
    </el-dialog>
</template>

<style lang="scss" scoped>
.dialog-header {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    gap: 16px;

    &--title {
        display: flex;
        align-items: center;
    }

    &--close {
        font-size: 18px;
    }

    &--close:hover {
        color: var(--el-color-primary);
    }
}
</style>